package roborally.program.text;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import roborally.program.CommandManager;
import roborally.program.command.Command;
import roborally.program.command.ExecutionCommand;
import roborally.program.command.SequenceCommand;
import roborally.program.command.BasicCondition.ConditionProcedure;
import roborally.program.command.ExecutionCommand.ExecutionProcedure;

//We gaan er van uit dat en commando woord steeds met een haakje begint en eindigt.
public enum TextFactory {
	
	EXECUTION{

		private Map<String, ExecutionProcedure> patterns;
		
		@Override
		public void setUp() {
			this.setSetUp();
			patterns = new HashMap<String, ExecutionProcedure>();
			for(ExecutionProcedure lusProc : ExecutionProcedure.values())
				patterns.put(lusProc.getStringPattern(), lusProc);
		}
		
		@Override
		public TextCommandPattern getPattern() {
			assert this.getSetUp();
			
			return new TextCommandPattern() {
				
				@Override
				public boolean matches(String word) {
					for(String pattern : patterns.keySet())
						if(Pattern.matches(pattern, word))
							return true;
					return false;
				}
				
				@Override
				public Command create(String word) {
					for(String pattern : patterns.keySet())
						if(Pattern.matches(pattern, word)) {
							ExecutionProcedure proc = patterns.get(pattern);
							ArrayList<Object> args = new ArrayList<Object>();
							String[] subword = word.replaceAll("\\(", " ").replaceAll("\\)"," ").trim().split("\\s++");
							for(int i = 1 ; i < subword.length; i++)
								args.add(proc.getValue(subword[i]));
							return new ExecutionCommand(proc, args.toArray());
						}
					throw new IllegalArgumentException("Word is not valid.\n" + word);
				}
			};
		}
	},
	SEQUENCE {

		private String pattern;
		
		@Override
		public TextCommandPattern getPattern() {
			assert getSetUp();
			return new TextCommandPattern() {
				
				//Enkel controle of aan het sequentie patroon voldaan is. Niet of er binnen de sequentie
				//een geldig patroon staat. Anders als we dit recursief doen, controleren we dat zeer veel.
				//Daarvoor moet er nog een parser komen die dat enkel doet.
				@Override
				public boolean matches(String word) {
					return Pattern.matches(pattern, word);
				}
				
				@Override
				public Command create(String word) throws IllegalArgumentException {
					if(matches(word)) {
						SequenceCommand sc = new SequenceCommand();
						word = word.replaceFirst("^(\\()(\\s*)(" + SequenceCommand.getWord() + ")", "");
						word = word.substring(0, word.length() - 1).trim();
						sc.addAsCommands(CommandManager.get().create(word));
						return sc;
					}
					throw new IllegalArgumentException();
				}
			};
		}

		@Override
		public void setUp() {
			this.setSetUp();
			pattern = "^(\\()(\\s*)(" + SequenceCommand.getWord() + ")(.*)(\\))";	
		}
		
	},
	BASIC_CONDITION {

		private Map<String, ConditionProcedure> patterns;
		
		@Override
		public void setUp() {
			this.setSetUp();
			patterns = new HashMap<String, ConditionProcedure>();
			for(ConditionProcedure lusProc : ConditionProcedure.values())
				patterns.put(lusProc.getStringPattern(), lusProc);			
		}

		@Override
		public TextCommandPattern getPattern() {
			assert getSetUp();
			return new TextCommandPattern() {
				
				@Override
				public boolean matches(String word) {
					// TODO Auto-generated method stub
					return false;
				}
				
				@Override
				public Command create(String word) {
					// TODO Auto-generated method stub
					return null;
				}
			};
		}
		
		
	};
	
	public boolean getSetUp() {
		return this.isSetUp;
	}
	
	public void setSetUp() {
		this.isSetUp = true;
	}
	
	private boolean isSetUp = false;
	
	private TextFactory() {
		this.setUp();
	}
	
	public abstract TextCommandPattern getPattern();
	
	public abstract void setUp();
	

}
